package cn.btks.resultintegration.util;

import org.apache.commons.codec.binary.Base64;

import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.security.Key;
import java.security.KeyFactory;
import java.security.spec.X509EncodedKeySpec;

/**
 * @author lly
 * @create 2020-06-23 14:34
 * 对接方调用示例
 **/
public class CryptoTestUtils {
    //非对称密钥算法
    private static final String KEY_ALGORITHM = "RSA";
    /**
     * RSA最大加密明文大小
     */
    private static final int MAX_ENCRYPT_BLOCK = 64;

    /**
     * RSA最大解密密文大小
     */
    private static final int MAX_DECRYPT_BLOCK = 128;

    /**
     * 公钥解密
     *
     * @param data
     * @return
     */
    public static String decryptByPublicKey(String data, String publicKey) {
        try {
            byte[] encryptedData = Base64.decodeBase64(data);
            byte[] keyBytes = Base64.decodeBase64(publicKey);
            X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
            Key publicK = keyFactory.generatePublic(x509KeySpec);
            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
            cipher.init(Cipher.DECRYPT_MODE, publicK);
            return new String(segmentCrypt(encryptedData, cipher,MAX_DECRYPT_BLOCK));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 公钥加密
     *
     * @param data
     * @return
     */
    public static String encryptByPublicKey(String data, String publicKey) {
        try {
            byte[] keyBytes = Base64.decodeBase64(publicKey);
            X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
            Key publicK = keyFactory.generatePublic(x509KeySpec);
            // 对数据加密
            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
            cipher.init(Cipher.ENCRYPT_MODE, publicK);
            return Base64.encodeBase64String(segmentCrypt(data.getBytes(), cipher,MAX_ENCRYPT_BLOCK));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 分段加密解密
     *
     * @param data
     * @param cipher
     * @return
     */
    private static byte[] segmentCrypt(byte[] data, Cipher cipher, int maxLen) {
        int inputLen = data.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        try {
            // 对数据分段加密
            while (inputLen - offSet > 0) {
                if (inputLen - offSet > maxLen) {
                    cache = cipher.doFinal(data, offSet, maxLen);
                    offSet += maxLen;
                } else {
                    cache = cipher.doFinal(data, offSet, inputLen - offSet);
                    offSet = inputLen;
                }
                out.write(cache, 0, cache.length);
            }
            byte[] encryptedData = out.toByteArray();
            out.close();
            return encryptedData;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
